package com.tengits.mqttmonitor.rnlibs.rs;

import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.util.Log;

import com.facebook.react.bridge.Arguments;

import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;

import java.io.IOException;

public class UsbSerialPortWrapper extends SerialPortBase implements TengitsSerialInputOutputManager.Listener{

    private static final int WRITE_WAIT_MILLIS = 2000;
    private static final int READ_WAIT_MILLIS = 2000;

    private TengitsSerialInputOutputManager usbIoManager;
    private UsbSerialPort usbSerialPort;

    public UsbSerialPortWrapper(ReactContext reactContext, final String key, int baudRate,
                                int parity, int dataBits, int stopBits, int port) throws IOException{
        super(reactContext, key, baudRate, parity, dataBits, stopBits);
        UsbDevice device = null;
        UsbManager usbManager = (UsbManager) reactContext.getSystemService(Context.USB_SERVICE);
        for(UsbDevice v : usbManager.getDeviceList().values())
        {
            Log.e("usb", v.getDeviceName());
//            if(v.getDeviceName().equals(key))
//            {
//                device = v;
//                break;
//            }
            device = v;
            break;
        }

        if(device == null) {
            throw new IOException();
        }
        UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);
        if(driver == null) {
            throw new IOException();
        }
        if(driver.getPorts().size() <= port) {
            throw new IOException();
        }
        usbSerialPort = driver.getPorts().get(port);
        UsbDeviceConnection usbConnection = usbManager.openDevice(driver.getDevice());
        if(usbConnection == null) {
            throw new IOException();
        }
        usbSerialPort.open(usbConnection);
        usbSerialPort.setParameters(baudRate, dataBits, stopBits, parity);
        usbIoManager = new TengitsSerialInputOutputManager(usbSerialPort, this);
        TengitsSerialInputOutputManager.DEBUG = true;
        usbIoManager.setReadTimeout(READ_WAIT_MILLIS);
        usbIoManager.setWriteTimeout(WRITE_WAIT_MILLIS);
        usbIoManager.start();
    }

    @Override
    public void writeHex(String buffer) throws IOException {
        if(usbSerialPort != null) {
            // usbSerialPort.write(buffer.getBytes(), WRITE_WAIT_MILLIS);
            //usbSerialPort.write(hexStringToByteArray(buffer), WRITE_WAIT_MILLIS);
            //usbIoManager.writeAsync(hexStringToByteArray(buffer));
            usbIoManager.writeAsync(hexStringToByteArray(buffer));
            Log.e("usb", "send: " + buffer);
        } else {
            throw new IOException("no serial port");
        }
    }

    @Override
    public boolean close(boolean isForce) {
        if(isForce || release() <= 0) {
            if(usbIoManager != null) {
                usbIoManager.setListener(null);
                usbIoManager.stop();
            }
            usbIoManager = null;
            try {
                usbSerialPort.close();
            } catch (IOException ignored) {}
            usbSerialPort = null;
            return true;
        }
        return false;
    }

    @Override
    public boolean isRunning() {
        return usbIoManager != null && usbIoManager.getState() == TengitsSerialInputOutputManager.State.RUNNING;
    }

    @Override
    public void onNewData(byte[] data) {
        WritableMap event = Arguments.createMap();
        event.putString("data", bytesToHex(data));
        event.putString("key", key);
        event.putString("type", "receive");
        sendEvent(DataReceivedEvent, event);
        Log.e("usb", "receive: " + bytesToHex(data));
    }

    @Override
    public void onRunError(Exception e) {
        WritableMap event = Arguments.createMap();
        event.putString("key", key);
        event.putString("data", e.getMessage());
        event.putString("type", "error");
        sendEvent(DataReceivedEvent, event);
        Log.e("usb", "error: " + e.getMessage());
    }

}
